package by.dkusch.aircompany.dao.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;

import org.hibernate.jpa.criteria.OrderImpl;
import org.springframework.stereotype.Repository;

import by.dkusch.aircompany.dao.PlaneDao;
import by.dkusch.aircompany.model.filter.FilterPlane;
import by.dkusch.aircompany.model.filter.base.FilterEntity;
import by.dkusch.aircompany.model.tables.Flight;
import by.dkusch.aircompany.model.tables.Flight_;
import by.dkusch.aircompany.model.tables.Plane;
import by.dkusch.aircompany.model.tables.PlaneType;
import by.dkusch.aircompany.model.tables.PlaneType_;
import by.dkusch.aircompany.model.tables.Plane_;
import by.dkusch.aircompany.model.tables.base.BaseEntity_;

@Repository
public class PlaneDaoImpl extends AbstractDaoImpl<Long, Plane> implements
		PlaneDao {

	public PlaneDaoImpl() {
		super(Plane.class);
	}

	@Override
	public List<Plane> getAllItemsWithFilter(SingularAttribute<? super Plane, ?> attr, boolean ascending, int startRecord, int pageSize, FilterEntity<Long, ? super Plane> filter) {
		if (filter == null) {
			return getAllItems(attr, ascending, startRecord, pageSize);
		}

		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<Plane> criteria = cBuilder.createQuery(Plane.class);
		Root<Plane> fromPlane = criteria.from(Plane.class);

		@SuppressWarnings("unchecked")
		Join<Plane, PlaneType> fromPlaneType = (Join<Plane, PlaneType>) fromPlane.fetch(Plane_.planeType, JoinType.LEFT);

		OrderImpl order = new OrderImpl(fromPlane.get(BaseEntity_.id), ascending);
		if (attr != null) {
			if (Plane_.planeType.equals(attr)) {
				order = new OrderImpl(fromPlaneType.get(PlaneType_.code), ascending);
			} else {
				order = new OrderImpl(fromPlane.get(attr), ascending);
			}
		}
		;

		List<Predicate> conditions = new ArrayList<Predicate>();

		FilterPlane fc = (FilterPlane) filter;

		if (fc.getCode() != null) {
			conditions.add(cBuilder.equal(cBuilder.upper(fromPlane.get(Plane_.code)), fc.getCode().toUpperCase()));
		}

		if (fc.getTypeCode() != null) {
			conditions.add(cBuilder.equal(cBuilder.upper(fromPlaneType.get(PlaneType_.code)), fc.getTypeCode().toUpperCase()));
		}

		if (fc.getName() != null) {
			conditions.add(cBuilder.like(cBuilder.upper(fromPlane.get(Plane_.name)), fc.getName().toUpperCase()));
		}

		TypedQuery<Plane> query = getEm().createQuery(criteria.select(fromPlane).where(cBuilder.and(conditions.toArray(new Predicate[] {}))).orderBy(order));

		if (startRecord >= 0) {
			query.setFirstResult(startRecord);
			query.setMaxResults(pageSize);
		}

		List<Plane> results = query.getResultList();
		return results;

	}

	@Override
	public boolean checkCanRemoveRecord(Plane entity) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();
		CriteriaQuery<Flight> criteria = cBuilder.createQuery(Flight.class);

		Root<Flight> fromFlight = criteria.from(Flight.class);
		Join<Flight, Plane> fromPlane = fromFlight.join(Flight_.plane);

		List<Predicate> conditions = new ArrayList<Predicate>();
		conditions.add(cBuilder.equal(fromPlane.get(Plane_.id), entity.getId()));

		TypedQuery<Flight> query = getEm().createQuery(criteria.select(fromFlight).where(cBuilder.and(conditions.toArray(new Predicate[] {}))));
		List<Flight> results = query.getResultList();
		return (results == null) || ((results != null) && (results.size() == 0));
	}

}
